package com.lin.security.util;

import com.lin.entity.User;
import com.lin.security.SecurityUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author linze
 * @version 1.0
 * @Description
 * @Date 2021/1/21 18:03
 */
public class JwtUtils {

    public static final String TOKEN_HEADER = "Authorization";
    public static final String TOKEN_PREFIX = "Bearer ";

    public static final String SUBJECT = "client";

    public static final long EXPIRITION = 1000 * 24 * 60 * 60 * 7;

    public static final String APPSECRET_KEY = "ptu_secret";

    private static final String ROLE_CLAIMS = "rol";

    public static String generateJsonWebToken(User user) {

        if (user.getUid() == null || user.getUsername()== null) {
            return null;
        }

        Map<String,Object> map = new HashMap<>();
        map.put(ROLE_CLAIMS,String.valueOf(user.getIdentity()));
        map.put(User.UID,user.getUid());
        map.put(User.IDENTITY,user.getIdentity());
        String token = Jwts
                .builder()
                .setSubject(SUBJECT)
                .setClaims(map)
                .claim(User.UID, user.getUid())
                .claim(User.USERNAME, user.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
                .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
        return token;
    }


    public static String createToken(SecurityUser securityUser, String role) {

        Map<String,Object> map = new HashMap<>();
        map.put(ROLE_CLAIMS, role);
        map.put(User.UID,securityUser.getUid());
        map.put(User.USERNAME,securityUser.getUsername());
        String token = Jwts
                .builder()
                .setClaims(map)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION))
                .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
        return token;
    }

    public static SecurityUser getSecurityUserFromToken(String token){
        SecurityUser user=null;

        try {
            final Claims claims = getClaimsFromToken(token);
            String username = claims.getSubject();
            String role= claims.get(ROLE_CLAIMS).toString();
            int uid =(int)claims.get(User.UID);
            user = new SecurityUser(uid,username,role);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return user;
    }

    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(APPSECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    private static Claims checkJWT(String token) {
        if(token==null) return null;
        try {
            return Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        } catch (ExpiredJwtException e) {
            return e.getClaims();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String getUsernameFromToken(String token){

        if(token==null) return null;
        Claims claims = checkJWT(token);
        return (String) claims.get(User.USERNAME);
    }
    public static Integer getUidFromToken(String token){

        if(token==null) return -1;
        Claims claims = checkJWT(token);
        return (Integer) claims.get(User.UID);
    }

    public static Integer getUserRole(String token){
        Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();
        return (Integer) claims.get(ROLE_CLAIMS);
    }


    public static boolean isTokenExpired(String token){
        Claims claims = checkJWT(token);
        return claims.getExpiration().before(new Date());
    }

    public static boolean isValidToken(String token, UserDetails userDetails) {
        SecurityUser userDetail = (SecurityUser) userDetails;
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetail.getUsername())
                && !isTokenExpired(token)
        );
    }




}


